#include <stdint.h>
#include "uint128.h"
#include <stdio.h>
#include <stdlib.h>

typedef uint128_t (*FP_div)(uint128_t n, uint128_t d);

void print_uint128(const char *prompt, uint128_t n)
{
    union
    {
        uint128_t tu;
        uint64_t  du[2];
    } t = {n};
    printf("%s:%lu:%lu\n",prompt,t.du[1],t.du[0]);

}

void verify(const char *prompt,uint128_t n, uint128_t d, FP_div fp)
{
    uint128_t q_ref= n/d;
    uint128_t q    = fp(n,d);
    if ( q_ref==q )
    {
        printf("%s:OK\n",prompt);
    }
    else
    {
        printf("%s:Error\n",prompt);
        print_uint128("q_ref", q_ref);
        print_uint128("q    ", q);
    }
}

void test_uint128_div(const char* fun_name, FP_div fp )
{
    printf("Is runing test on function %s\n",fun_name);

    union
    {
        uint128_t tu;
        uint64_t  du[2];
    } n,d;
    
    //the test cases for  n<d
    n.du[1]=0; n.du[0]=0;
    d.du[1]=0; d.du[1]=1;
    verify("case 1",n.tu,d.tu,fp);
    
    n.du[1]=0; n.du[0]=1;
    d.du[1]=1; d.du[0]=1;
    verify("case 2",n.tu,d.tu, fp);
    
    n.du[1]=1; n.du[0]=5;
    d.du[1]=1; d.du[0]=10;
    verify("case 3",n.tu,d.tu, fp);
    
    n.du[1]=3;  n.du[0]=-1;
    d.du[1]=5;  d.du[0]=5678;
    verify("case 4",n.tu,d.tu, fp);
    
    //the test cases for XX/YY
    n.du[1]=58679;  n.du[0]=1;
    d.du[1]=3;      d.du[0]=5678;
    verify("case 5",n.tu,d.tu, fp);
    
    n.du[1]=3;      n.du[0]=5678;
    d.du[1]=3;      d.du[0]=5677;
    verify("case 6",n.tu,d.tu, fp);
    
    n.du[1]=3;      n.du[0]=5678;
    d.du[1]=3;      d.du[0]=5678;
    verify("case 7",n.tu,d.tu, fp);
    
    n.du[1]=-1;    n.du[0]=-1;
    d.du[1]=1;     d.du[0]=1;
    verify("case 8",n.tu,d.tu, fp);
    
    n.du[1]=-1;     n.du[0]=-1;
    d.du[1]=1;      d.du[0]=3;
    verify("case 9",n.tu,d.tu, fp);
    
    //the test cases for XX/0Y
    n.du[1]=3;  n.du[0]=-1;
    d.du[1]=0;  d.du[0]=57;
    verify("case 10",n.tu,d.tu, fp);
    
    n.du[1]=33498764;  n.du[0]=1234;
    d.du[1]=0;         d.du[0]=57;
    verify("case 11",n.tu,d.tu, fp);
    
    //the test cases for 0X/0Y
    n.du[1]=0;  n.du[0]=10;
    d.du[1]=0;  d.du[0]=10;
    verify("case 12",n.tu,d.tu, fp);
    
    n.du[1]=0;  n.du[0]=13;
    d.du[1]=0;  d.du[0]=3;
    verify("case 13",n.tu,d.tu, fp);
    
    n.du[1]=0;  n.du[0]=155;
    d.du[1]=0;  d.du[0]=31;
    verify("case 14",n.tu,d.tu, fp);

    n.du[1]=9223372036854775808ul;  n.du[0]=155;
    d.du[1]=9223372036854775808ul;  d.du[0]=31;
    verify("case 15",n.tu,d.tu, fp);
}

int main(int argc, char* argv[])
{
    test_uint128_div("uint128_div_v0_bitbybit", uint128_div_v0_bitbybit);
    test_uint128_div("uint128_div_v1_asm", uint128_div_v1_asm);
    test_uint128_div("uint128_div_v2_asm", uint128_div_v2_asm);
    return 0;
}


